package com.tuling.service.impl;

import com.tuling.common.Result;
import com.tuling.mapper.QuestionMapper;
import com.tuling.pojo.Question;
import com.tuling.pojo.QuestionExample;
import com.tuling.service.QuestionService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Service
public class QuestionServiceImpl implements QuestionService {

    DelayQueue<DelayTask> delayQueue = new DelayQueue<>();

    volatile static Question cacheQuestion = null;

    volatile static Question cacheQuestionNoValue = null;

    @Resource
    private QuestionMapper questionMapper;


    /**
     * 获取问题，保证12小时内获取到的只有一个问题
     *
     * @param type 问题类别（JVM,MySQL,Spring,KafKa,MQ,,Redis,,ZK,分库分表,并发专题,微服务,计算机基础）
     * @return
     */
    @Override
    public Result<Question> question(String type) {
        if (cacheQuestion != null) {
            // 并发安全忽略不计，价格校验就好了，就几个人用，而且就算增加了2个延时任务也无所谓
            if (delayQueue.size() > 0) {
                return Result.ok(cacheQuestionNoValue);
            }
            delayQueue.put(new DelayTask());
            // 延时任务删除缓存，默认12小时删除
            Executors.newSingleThreadExecutor().execute(this::excuteThread);
            return Result.ok(cacheQuestionNoValue);
        }
        if (StringUtils.isBlank(type)) {
            return Result.fail("问题类别不能为空");
        }
        QuestionExample questionExample = new QuestionExample();
        QuestionExample.Criteria criteria = questionExample.createCriteria();
        criteria.andBelongSubjectEqualTo(type).andIsUsedEqualTo("0");
        List<Question> questions = questionMapper.selectByExampleWithBLOBs(questionExample);
        if (CollectionUtils.isEmpty(questions)) {
            return Result.fail("无该类别题目或者该类别题目已答完，请换类别");
        }
        Question question = questions.get(0);
        cacheQuestion = new Question();
        BeanUtils.copyProperties(question, cacheQuestion);
        question.setQuestionValue(null);
        cacheQuestionNoValue = question;
        // 将当前问题是否使用字段改为已使用
        question.setIsUsed("1");
        questionMapper.updateByPrimaryKey(question);
        // 异步删除缓存，默认凌晨5点删除
        delayQueue.put(new DelayTask());
        Executors.newSingleThreadExecutor().execute(this::excuteThread);
        return Result.ok(question);
    }

    class DelayTask implements Delayed {

        //任务的延时时间，单位毫秒
        private Long expire = null;

        @Override
        public long getDelay(TimeUnit unit) {
            if (expire == null) {
                // 当前问题查询默认为第二天的凌晨5点删除
                expire = LocalDate.now().atTime(LocalTime.of(5, 0)).plusDays(1).toInstant(ZoneOffset.of("+8")).toEpochMilli();
            }
            return unit.convert(this.expire - System.currentTimeMillis(), unit);
        }

        @Override
        public int compareTo(Delayed o) {
            long delta = getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS);
            return (int) delta;
        }
    }

    /**
     * 延时任务执行线程
     */
    private void excuteThread() {
        while (true) {
            try {
                delayQueue.take();
                cacheQuestion = null;
                cacheQuestionNoValue = null;
            } catch (InterruptedException e) {
                break;
            }
        }
    }

    /**
     * 获取缓存问题
     */
    @Override
    public Question getCacheQuestion() {
        return cacheQuestion;
    }

    /**
     * 删除缓存
     */
    @Override
    public void clearCache() {
        cacheQuestion = null;
        cacheQuestionNoValue = null;
    }

    /**
     * 根据条件查询问题列表
     */
    @Override
    public List<Question> queryByExample(QuestionExample questionExample) {
        return questionMapper.selectByExampleWithBLOBs(questionExample);
    }
}
